﻿#include "stdafx.h"

#include <string>
#include "../Services.h"

#pragma comment(lib, "IPHLPAPI.lib")


void HelloService::hello()
{
	try
	{
		asio::io_service io_service;
		unsigned short port = 2011;
		asio::ip::udp::endpoint ip(asio::ip::address_v4::from_string(findPhysicsNetworkAdapters()), port);
		asio::ip::udp::socket udp_socket(io_service);
		udp_socket.open(ip.protocol());
		asio::error_code ec;
		do {
			udp_socket.bind(ip, ec);
			ip.port(++port);
		} while (ec);
		//设置广播
		asio::socket_base::broadcast option(true);
		udp_socket.set_option(option);
		asio::ip::udp::endpoint broadcast_add(asio::ip::address_v4::broadcast(), 1745 /*htons(1745)*/);
		

		//BYTE receive_buffer[] = {'L','e','D','i','a','n','R','e','m','o','t','e','C','o','n','t','r','o','l'};
		char receive_buffer[100] = { 0 };
		isRun = true;
		//NetServer::endPoint.port();
		sprintf_s(receive_buffer, "LeDianRemoteControl:%d", _serverEndPoint.port());		
		_semaphore.Signal();
		while (true)
		{
			std::unique_lock<std::mutex> lock(mtx);
			if (!isRun)
			{				
				break;
			}
			udp_socket.send_to(asio::buffer(receive_buffer, strlen(receive_buffer)), broadcast_add);
			std::this_thread::sleep_for(std::chrono::milliseconds(100));
		}
		udp_socket.close();
	}
	catch (std::exception&)
	{
		_semaphore.Signal();
	}
}

HelloService::HelloService(const tcp::endpoint & endPoint) :_serverEndPoint(endPoint) {}

void HelloService::start()
{
	if (!isRun)
	{
		m_thrd = std::thread(std::bind
		(&HelloService::hello, this));
		_semaphore.Wait();
	}
}

void HelloService::restart(const tcp::endpoint & endPoint)
{
	if (!isRun)
	{
		_serverEndPoint = endPoint;
		m_thrd = std::thread(std::bind
		(&HelloService::hello, this));
		_semaphore.Wait();
	}
}

typedef struct _tagNetInf
{
	DWORD Characteristics;
	std::wstring RootDevice;
	_tagNetInf(DWORD _Characteristics, wchar_t *_RootDevice) :Characteristics(_Characteristics), RootDevice(_RootDevice), next(nullptr)
	{
	}
	_tagNetInf* next;
}NetInf, *PNetInf;

void GetNetInf(PNetInf &netinf)
{
	wchar_t *KeyPath = LR"(SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318})";
	//wchar_t *KeyPathStr = LR"(SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}\)";
	HKEY hKey1, hKey2, hKey3;
	LSTATUS lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyPath, 0, KEY_READ | KEY_WOW64_64KEY, &hKey1);
	if (lRet == ERROR_SUCCESS)
	{
		int idx = 0;
		DWORD idLenght = 10;
		wchar_t idStr[5] = { 0 };
		FILETIME ftLastWriteTime;
		std::wstring netPath;
		PNetInf tpnetinf = nullptr;
		while (RegEnumKeyEx(hKey1, idx++, idStr, &idLenght, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS)
		{
			if (RegOpenKeyEx(hKey1, idStr, 0, KEY_READ | KEY_WOW64_64KEY, &hKey2) == ERROR_SUCCESS)
			{
				DWORD dwType = REG_DWORD;
				DWORD dwSize = sizeof(DWORD);
				DWORD dwValue;
				if (::RegQueryValueEx(hKey2, L"Characteristics", NULL, &dwType, reinterpret_cast<LPBYTE>(&dwValue), &dwSize) == ERROR_SUCCESS)
				{
					if (RegOpenKeyEx(hKey2, L"Linkage", 0, KEY_READ | KEY_WOW64_64KEY, &hKey3) == ERROR_SUCCESS)
					{
						dwType = REG_MULTI_SZ;
						wchar_t tpbuf[64] = { 0 };
						dwSize = 64 * sizeof(wchar_t);
						LRESULT ec;
						if ((::RegQueryValueEx(hKey3, L"RootDevice", NULL, &dwType, reinterpret_cast<LPBYTE>(tpbuf), &dwSize)) == ERROR_SUCCESS)
						{
							if (tpnetinf == nullptr)
							{
								netinf = new NetInf(dwValue, tpbuf);
								tpnetinf = netinf;
							}
							else
							{
								tpnetinf->next = new NetInf(dwValue, tpbuf);
								tpnetinf = tpnetinf->next;
							}
						}
						RegCloseKey(hKey3);
					}
				}
				RegCloseKey(hKey2);
			}
			idLenght = 10;
			ZeroMemory(idStr, idLenght);
		}
	}
	RegCloseKey(hKey1);
}

bool IsPhysicsAdapter(PNetInf netinf, std::wstring adaptername)
{
	bool bRet = false;
	while (netinf)
	{
		if (adaptername == netinf->RootDevice)
		{
			if ((netinf->Characteristics & 0x04) == 0x04)//Characteristics=0x00000084
				bRet = true;
			break;
		}
		netinf = netinf->next;
	}
	return bRet;
}

#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) 
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

std::string HelloService::findPhysicsNetworkAdapters()
{
	PNetInf netinf = nullptr;
	GetNetInf(netinf);

	// 	PIP_INTERFACE_INFO pInfo = NULL;
	// 	ULONG ulOutBufLen = 0;
	// 
	// 	DWORD dwRetVal = 0;
	// 	int iReturn = 1;
	// 
	// 	int i;
	// 
	// 	// Make an initial call to GetInterfaceInfo to get
	// 	// the necessary size in the ulOutBufLen variable
	// 	dwRetVal = GetInterfaceInfo(NULL, &ulOutBufLen);
	// 	if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
	// 		pInfo = (IP_INTERFACE_INFO *)MALLOC(ulOutBufLen);
	// 		if (pInfo == NULL) {
	// 		}
	// 	}
	// 	// Make a second call to GetInterfaceInfo to get
	// 	// the actual data we need
	// 	dwRetVal = GetInterfaceInfo(pInfo, &ulOutBufLen);



		//PIP_ADAPTER_INFO结构体指针存储本机网卡信息
	PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO();
	//得到结构体大小,用于GetAdaptersInfo参数
	unsigned long stSize = sizeof(IP_ADAPTER_INFO);
	//调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量;其中stSize参数既是一个输入量也是一个输出量
	int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);

	if (ERROR_BUFFER_OVERFLOW == nRel)
	{
		//如果函数返回的是ERROR_BUFFER_OVERFLOW
		//则说明GetAdaptersInfo参数传递的内存空间不够,同时其传出stSize,表示需要的空间大小
		//这也是说明为什么stSize既是一个输入量也是一个输出量
		//释放原来的内存空间
		delete pIpAdapterInfo;
		//重新申请内存空间用来存储所有网卡信息
		pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize];
		//再次调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量
		nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize);
	}
	PIP_ADAPTER_INFO pFirstIpAdapterInfo = pIpAdapterInfo;
	if (ERROR_SUCCESS == nRel)
	{
		while (pIpAdapterInfo)
		{
			IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList);
			do
			{
				if (strcmp(pIpAddrString->IpMask.String, "255.255.255.0") == 0)
				{
					std::string ip = pIpAddrString->IpAddress.String;
					if (pFirstIpAdapterInfo)
					{
						delete pFirstIpAdapterInfo;
					}
					return ip;
				}
				pIpAddrString = pIpAddrString->Next;
			} while (pIpAddrString);

			pIpAdapterInfo = pIpAdapterInfo->Next;
		}
	}
	//释放内存空间
	if (pFirstIpAdapterInfo)
	{
		delete pFirstIpAdapterInfo;
	}

	return std::string();

}

void HelloService::stop()
{
	std::unique_lock<std::mutex> lock(mtx);
	isRun = false;
	//thrd.interrupt();
	/** join函数，作用是等待直到线程执行结束；可不加，但不能保证退出Destroy函数前线程被终结 */
	m_thrd.join();
}

bool HelloService::IsRuning()
{
	std::unique_lock<std::mutex> lock(mtx);
	return isRun;
}
